package com.xw.unification.helper;

import com.xw.unification.entity.SignatureCheckContext;
import com.xw.unification.enums.SignatureOperation;
import com.xw.unification.enums.SortType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

public class SignatureHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(SignatureHelper.class);

    private static final char K_V_SPLITTER = '=';

    private static final char K_V_PAIR_SPLITTER = '&';

    private static final char[] K_V_PAIR_SPLITTERS = {K_V_PAIR_SPLITTER};

    public String signature(String queryString, SignatureCheckContext checkContext) {
        if (!StringHelper.hasText(queryString) || checkContext == null) {
            return null;
        }
        // 获取所有参数
        Map<String, List<String>> paramMap = getQueryParamMap(queryString,
                checkContext.getCharsetName(), checkContext.isIgnoreEmptyValue());

        // 处理 validation signature
        String keyName = checkContext.getValidationSignatureName();
        String validation = null;
        List<String> valueList = paramMap.get(keyName);
        List<String> keyList = new ArrayList<>(paramMap.keySet());
        if (valueList == null || valueList.size() != 1) {
            validation = setValueWhenNoOrMultiValidation(keyName, valueList == null ? new ArrayList<>() : new ArrayList<>(valueList));
        } else {
            validation = valueList.get(0);
        }
        LOGGER.debug("validation signature: {}", validation);
        checkContext.setValidation(validation);
        keyList.remove(keyName);

        // 处理 signature key
        if (checkContext.isHasSignatureKey()) {
            keyName = checkContext.getSignatureKeyName();
            valueList = paramMap.get(keyName);
            String value;
            if (valueList == null || valueList.size() != 1) {
                value = handleWhenNoOrMultiSignatureKey(keyName, valueList == null ? new ArrayList<>() : new ArrayList<>(valueList));
                if (StringHelper.hasText(value)) {
                    valueList = new ArrayList<>();
                    valueList.add(value);
                    paramMap.put(keyName, valueList);
                    checkContext.setSignatureKeyValue(value);
                }
            } else {
                value = valueList.get(0);
                checkContext.setSignatureKeyValue(value);
            }
            if (!checkContext.isSignatureKeyInSort()) {
                keyList.remove(keyName);
            }
            LOGGER.debug("signature key: {}", valueList);
        }

        // 去除忽略的参数
        List<String> ignoreParamNames = checkContext.getIgnoreParamNames();
        for (String paramName : ignoreParamNames) {
            keyList.remove(paramName);
        }

        // 排序
        boolean asc = !SortType.DESC.equals(checkContext.getParamNameSort());
        keyList = keyList.stream().filter(Objects::nonNull).sorted((pre, cur) -> {
            if (Objects.equals(pre, cur)) {
                return 0;
            }
            return (asc ? 1 : -1) * pre.compareTo(cur);
        }).collect(Collectors.toList());
        if (checkContext.isHasSignatureKey() && !checkContext.isSignatureKeyInSort()) {
            keyList.add(checkContext.getSignatureKeyName());
        }

        // 重新拼接 queryString
        StringBuilder builder = new StringBuilder();
        for (String key : keyList) {
            valueList = paramMap.getOrDefault(key, Collections.emptyList());
            if (valueList.isEmpty() && checkContext.isIgnoreEmptyValue()) {
                continue;
            }
            for (String value : valueList) {
                builder.append(key);
                builder.append(K_V_SPLITTER);
                builder.append(value);
                builder.append(K_V_PAIR_SPLITTER);
            }
        }
        if (builder.length() > 0) {
            builder.deleteCharAt(builder.length() - 1);
        }

        // 执行操作
        String content = builder.toString();
        LOGGER.debug("sorted: {}", content);
        List<SignatureOperation> operations = checkContext.getOperations();
        if (operations != null) {
            LOGGER.debug("signature operations: {}", operations);
            for (SignatureOperation operation : operations) {
                if (operation != null) {
                    content = operation.apply(content, checkContext);
                }
            }
        }
        LOGGER.debug("signature result: {}", content);
        return content;
    }

    public Map<String, List<String>> getQueryParamMap(String queryString, String encodingType, boolean ignoreEmptyValue) {
        try {
            queryString = URLDecoder.decode(Optional.ofNullable(queryString).orElse(""), encodingType);
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported encoding type: " + encodingType, e);
        }
        Map<String, List<String>> map = new HashMap<>();
        StringBuilder keyBuilder = new StringBuilder();
        StringBuilder valueBuilder = new StringBuilder();
        List<String> valueList = null;
        char ch;
        boolean readValue = false;
        for (int i = 0; i < queryString.length(); i++) {
            ch = queryString.charAt(i);
            if (!readValue) {
                // 读 key
                if (ch != K_V_SPLITTER) {
                    keyBuilder.append(ch);
                } else {
                    // 切换读 value
                    readValue = true;
                    valueList = map.getOrDefault(keyBuilder.toString(), new ArrayList<>());
                }
            } else {
                // 读 value
                if (isInCharArray(K_V_PAIR_SPLITTERS, ch)) {
                    // 切换读 key
                    if (valueList != null && (!ignoreEmptyValue || valueBuilder.length() > 0)) {
                        valueList.add(valueBuilder.toString());
                    }
                    valueBuilder.delete(0, valueBuilder.length());
                    if (valueList != null && !valueList.isEmpty() && keyBuilder.length() > 0) {
                        map.put(keyBuilder.toString(), valueList);
                    }
                    keyBuilder.delete(0, keyBuilder.length());
                    readValue = false;
                } else {
                    valueBuilder.append(ch);
                }
            }
        }
        if (valueList != null && (!ignoreEmptyValue || valueBuilder.length() > 0)) {
            valueList.add(valueBuilder.toString());
        }
        if (valueList != null && !valueList.isEmpty() && keyBuilder.length() > 0) {
            map.put(keyBuilder.toString(), valueList);
        }
        return map;
    }

    private boolean isInCharArray(char[] charArray, char ch) {
        if (charArray == null) {
            return false;
        }
        for (char c : charArray) {
            if (c == ch) {
                return true;
            }
        }
        return false;
    }

    protected String setValueWhenNoOrMultiValidation(String key, List<String> valueList) throws RuntimeException {
        return null;
    }

    /**
     * 包含 SignatureKey 时, 请求中缺少 SignatureKey 或有多个 SignatureKey 的 value 时, 如何处理
     *
     * @param key
     * @param valueList
     * @throws RuntimeException
     */
    protected String handleWhenNoOrMultiSignatureKey(String key, List<String> valueList) throws RuntimeException {
        return null;
    }
}
